-- EvilStatueM
-- Create by cheny3
-- 雕像

module("EvilStatueM", package.seeall);

-- 所有的雕像配置信息
local evilStatues = {};
local evilItems = {};
local statueMap = {};
local itemsId = {};

local whenStartFloor;

-- 载入配置表
local _init = false;
local loadCsv = function()
    if _init then return end
    _init = true;

    evilStatues = {};
    evilItems = {};
    statueMap = {};

    -- 转换下信息表
    local evil_statue_CSV = get_evil_statue_CSV();
    for i = 1, #evil_statue_CSV do
        local row = evil_statue_CSV[i];
        evilStatues[row.id] = row;

        local class = row.classify;
        statueMap[class] = statueMap[class] or {};

        statueMap[class][row.level] = row;
    end

    local evil_items_CSV = get_evil_statue_items_CSV();
    for i = 1, #evil_items_CSV do
        local row = evil_items_CSV[i];
        evilItems[row.id] = row;
        itemsId[row.submit_id] = row;
    end

    evil_statue_CSV = {};
    evil_items_CSV = {};
end

-- 模块初始化
function init()
    loadCsv();

    EventMgr.removeAll("EvilStatueM");
    -- 离开迷宫回调
    EventMgr.register("EvilStatueM", event.LEAVE_DUNGEON, function()
        -- 删除当前exp值
        ME.user.dbase:delete("evil_statue_exp");
    end);

    -- 迷宫准备好
    EventMgr.register("EvilStatueM", event.DUNGEON_AREADY, whenStartFloor);
end

-- 开始迷宫
whenStartFloor = function()
    -- TODO
end

-- 计算雕像的奖励
function calcStatueBonus(who, id)
    local bonus = query(id, "bonus");

    -- 公式
    if type(bonus) == "string" then
        return FormulaM.invoke(bonus, who);
    end

    -- 配置的
    return bonus;
end

-- 检索
function query(classId, path)
    local m = evilStatues[classId];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 检索
function queryItem(classId, path)
    local m = evilItems[classId];

    if not m or not path then
        return m;
    end

    return m[path];
end

-- 根据类型检索
function queryStatue(class, level)
    local m = statueMap[class];

    if not m or not level then
        return m;
    end

    return m[level];
end

-- 获取雕像奖励描述
function getStatueBonusDesc(class, level)
    local m = queryStatue(class, level);

    if not m then
        return;
    end

    local desc = m["desc"];

    local prefix = "formula_";
    -- 如果配置了公式，则调用公式计算
    if type(desc) == "string" and string.startWith(desc, "formula_") then
        local formulaName = string.sub(desc, string.len(prefix) + 1);
        desc = FormulaM.invoke(formulaName, class, level);
    end

    return desc;
end

-- 获取等级限制
function getLimitLevel(class)
    local limitLevel = queryStatue(class, 1)["limit_level"];
    if type(limitLevel) == "string" and limitLevel ~= "" then
        limitLevel = FormulaM.invoke(limitLevel);
    end

    return limitLevel;
end

-- 判断某雕像是否已经满级了
function isTopLevel(class)
    local evilExp = ME.user.dbase:query("evil_statue_exp", {});
    local curExp   = evilExp[class] or 0;
    local maxLevel = #table.keys(statueMap[class]);

    local limitLevel = queryStatue(class, 1)["limit_level"];
    if type(limitLevel) == "string" and limitLevel ~= "" then
        limitLevel = FormulaM.invoke(limitLevel);
    end

    if type(limitLevel) == "number" then
        return curExp >= statueMap[class][limitLevel]["exp"];
    end

    return curExp >= statueMap[class][maxLevel]["exp"];
end

-- 获取信息(当前等级、历史最高等级)
function getStatueInfo(class)
    local evilExp    = ME.user.dbase:query("evil_statue_exp", {});
    local evilStatue = ME.user.dbase:query("evil_statue", {});
    local curExp = evilExp[class] or 0;
    local maxLevel = evilStatue[class] or 0;
    local data = statueMap[class];
    local ret = {
        ["max_level"] = maxLevel,
        ["cur_level"] = 0,
        ["exp"]       = curExp,
    };

    local maxLevel = getLimitLevel(class) or #data;
    for level = 1, maxLevel do
        if data[level]["exp"] <= curExp then
            ret["cur_level"] = level;
        else
            break;
        end
    end

    return ret;
end

-- 计算物品的exp
function calcItemsExp(items)
    return FormulaM.invoke("CALC_EVIL_ITEMS_EXP", items);
end

-- 判断能否提交意见装备
function canSubmit(pos, items)
    local grid = DungeonM.getGridByPos(pos);

    -- 如果格子不是
    if grid.type ~= GRID_TYPE_EVIL_STATUE or
        grid.state == GRID_STATE_DISABLE then
        trace("EvilStatueM", "格子类型不对。");
        return false;
    end

    if grid.active ~= 1 then
        trace("EvilStatueM", "雕像尚未激活，不能提交装备。");
        return false;
    end

    local classify = grid.classify;
    local needAmount = {};
    for _, classId in pairs(items) do
        needAmount[classId] = tonumber(needAmount[classId]) + 1;
        if queryItem(classId, "classify") ~= classify then
            trace("EvilStatueM", "物品%d不是雕像%s指定物品，不能提交。", classId, classify);
            return false;
        end

        if ItemM.getAmount(ME.user, classId) < needAmount[classId] then
            trace("EvilStatueM", "物品%d不足，不能提交。", classId);
            return false;
        end
    end

    if isTopLevel(classify) then
        trace("EvilStatueM", "雕像%s满级，不能提交。", classify);
        return false;
    end

    return true;
end

-- 提交装备
function submitItems(pos, items)
    -- 遍历所有的装备
    if not canSubmit(pos, items) then
        return false;
    end

    for _, classId in pairs(items) do
        -- 扣除物品
        ItemM.costAmount(ME.user, classId, 1);
    end

    -- 增加exp
    local grid = DungeonM.getGridByPos(pos);
    local addExp = calcItemsExp(items);
    local upgradeLevel, bonusList = tryUpgrade(addExp, grid.classify);

    -- 抛出献祭事件
    EventMgr.fire(event.EVIL_STATUE_SUBMIT, {
        ["isUpgrade"] = upgradeLevel > 0,
        ["classify"] = grid.classify,
        ["upgradeLevel"] = upgradeLevel,
        ["bonusList"] = bonusList,
        ["pos"] = pos, });

    return true;
end

-- 尝试升级
function tryUpgrade(exp, class)
    local evilExp = ME.user.dbase:query("evil_statue_exp", {});
    local evilStatue = ME.user.dbase:query("evil_statue", {});

    -- 当前exp
    local curExp = evilExp[class] or 0;
    local nextExp = curExp + exp;
    local curLevel = 0;
    local data = statueMap[class];
    local maxLevel = getLimitLevel(class) or #data;

    local upgradeLevel = 0;
    local bonusList = {};

    -- 先修改当前的exp
    evilExp[class] = nextExp;
    ME.user.dbase:set("evil_statue_exp", evilExp);

    -- 奖励
    for level = 1, maxLevel do

        BonusM.clearBonusCollect();
        BonusM.startBonusCollect();

        local requireExp = data[level]["exp"];

        if requireExp > curExp and requireExp <= nextExp then
            -- 奖励
            doBonus(data[level]["id"]);

            -- 等级
            curLevel = level;

            BonusM.endBonusCollect();
            local bonus = BonusM.getBonusCollect();

            BonusM.clearBonusCollect();

            upgradeLevel = upgradeLevel + 1;
            table.insert(bonusList, bonus);
        elseif requireExp > nextExp then
            -- 超出的部分就不用管了
            break;
        end
    end

    BonusM.endBonusCollect();
    BonusM.clearBonusCollect();

    -- 曾经达到的最高等级
    local everLevel = evilStatue[class] or 0;
    evilStatue[class] = math.max(everLevel, curLevel);
    ME.user.dbase:set("evil_statue", evilStatue);

    -- 抛出事件
    EventMgr.fire(event.EVIL_STATUE_UPGRADE, {
        ["class"] = class,
        ["level"] = curLevel,});

    return upgradeLevel, bonusList;
end

-- 奖励
function doBonus(id)
    local info = calcStatueBonus(ME.user, id);
    local keys = table.keys(info);
    table.sort(keys);

    for i = 1, #keys do
        local key = keys[i];
        local value = info[key];

        if key == "bonus" then
            local arr = value;
            if type(arr[1]) ~= "table" then
                arr = { value, };
            end

            for _, bonus in pairs(arr) do
                BonusM.doBonus(bonus, "evil_statue_bonus");
            end
        end
    end
end

-- 把装备列表处理成参数
function changeItemsToArgs(submitList)
    table.sort(submitList);
    local arg = 0;
    local num = 1;
    for _, classId in pairs(submitList) do
        local id = queryItem(classId, "submit_id");
        arg = id * num + arg;
        num = num * 100;
    end
    return arg;
end

-- 把参数处理成装备列表
function changeArgsToItem(args)
    local items = {};
    local num = 10000;
    for i = 1, 3 do
        local id = math.floor(args / num);
        local classId = (itemsId[id] or {})["id"];
        if classId then
            table.insert(items, classId);
        end
        args = args - num * id;
        num = num / 100;
    end
    table.sort(items);
    return items;
end

-- 获取提交列表
function getSubmitItems(classify)
    local ret = {};
    for classId, info in pairs(evilItems) do
        if info["classify"] == classify then
            table.insert(ret, classId);
        end
    end

    return ret;
end

-- 能否激活
function canActiveEvilStatue(pos)
    local grid = DungeonM.getGridByPos(pos);

    -- 如果格子不是
    if grid.type ~= GRID_TYPE_EVIL_STATUE or
        grid.state == GRID_STATE_DISABLE then
        trace("EvilStatueM", "格子类型不对。");
        return false;
    end

    if grid.active == 1 then
        trace("EvilStatueM", "雕像已经激活，不能再次激活。");
        return false;
    end

    -- 不允许激活的出战宠物
    local element = grid.element;
    local dbase = DungeonM.queryElement(element, "dbase");
    local unablePet = dbase["unable_pet"] or {};
    local activePet = ME.user.dbase:query("active_pet");
    if table.indexOf(unablePet, activePet) >= 0 then
        trace("EvilStatueM", "不允许宠物%s激活雕像。", PetM.query(activePet, "name"));
        return false;
    end

    return true;
end

-- 激活邪神雕像
function activeEvilStatue(pos)
    if true ~= canActiveEvilStatue(pos) then
        return false;
    end

    -- 标记为激活
    local grid = DungeonM.getGridByPos(pos);
    grid.active = 1;

    -- 奖励
    local info = grid.bonus or {};
    if type(info[1]) == 'number' then
         -- 只有一种奖励
        BonusM.doBonus(info, "evil_active");
    else
        -- 有多种奖励
        for _, bonus in pairs(info) do
            BonusM.doBonus(bonus, "evil_active");
        end
    end

    -- 为了表示激活过
    local evilExp = ME.user.dbase:query("evil_statue_exp", {});
    local classify = grid.classify;
    evilExp[classify] = 0;
    ME.user.dbase:set("evil_statue_exp", evilExp);

    -- 激活
    EventMgr.fire(event.ACTIVE_EVIL_STATUE, {["pos"] = pos, ["bonus"] = info});

    return true;
end

-- 是否非法
function isInvalid(dbase)
    local classify = dbase.classify;
    if hasActiveStatue(classify) then
        -- 已经激活了，是合法的
        return false;
    end

    local layer = DungeonM.currentLayer();
    if not type(dbase["active_layer"]) == "number"
        or layer == dbase["active_layer"] then
        -- 在激活层或者没有激活层配置，是合法的
        return false;
    end

    -- 非法
    return true;
end

-- 初始化格子数据
function initGridData(dbase)
    -- 数据
    local classify = dbase.classify;
    if hasActiveStatue(classify) then
        -- 已经激活了
        return { ["active"] = 1 };
    end

    return {};
end

-- 当前是否有相关类型的数据
function hasActiveStatue(classify)
    local evilExp = ME.user.dbase:query("evil_statue_exp", {});
    if type(evilExp[classify]) == "number" then
        return true;
    end
    return false;
end